use serde_json;
use std::collections::HashMap;
use std::fs;
use std::path::Path;
pub fn check_id_card(id_card_no: &str) -> String {
    let file_path = "LocationId.json";
    let location_map = location_id_parser(file_path);

    if id_card_no.len() != 18 && id_card_no.len() != 15 {
        return "身份证号码错误".to_string();
    }
    else{
        let location_id = id_card_no[..6].parse::<i32>().unwrap();
        let identity_card: IdentityCard;
        if id_card_no.len() == 18 {
            if !id_card_no[..17].chars().all(|c| c.is_digit(10)) || !(id_card_no[17..].chars().all(|c| c.is_digit(10)) || id_card_no[17..].to_string() == "X"){
                return "身份证号码错误".to_string();
            }
            else {
                let birth = id_card_no[6..14].parse::<i32>().unwrap();
                let sequence_code = id_card_no[14..17].parse::<i32>().unwrap();
                let check_code = id_card_no[17..].to_string();
                identity_card = IdentityCard::new(location_id, birth, sequence_code, check_code);
            }
        }
        else{
            if !id_card_no[..14].chars().all(|c| c.is_digit(10)) || !(id_card_no[14..].chars().all(|c| c.is_digit(10)) || id_card_no[14..].to_string() == "X"){
                return "身份证号码错误".to_string();
            }
            let birth = id_card_no[6..12].parse::<i32>().unwrap();
            let sequence_code = id_card_no[12..14].parse::<i32>().unwrap();
            let gender = id_card_no[14..].to_string();
            identity_card = IdentityCard::new(location_id, birth, sequence_code, gender);
        }
        if identity_card.get_location(&location_map) == "Unknown" {
            println!("location_id:{}, location_map: {}", location_id, identity_card.get_location(&location_map));
            return "身份证号码错误".to_string();
        }
        else if identity_card.birth_valid_check() == false {
            println!("birth_year:{}, birth_month:{}, birth_day:{}", identity_card.get_birth().0, identity_card.get_birth().1, identity_card.get_birth().2);
            return "身份证号码错误".to_string();
        }
        else if id_card_no.len() == 18 && identity_card.sequence_code_valid_check() == false {
            return "身份证号码错误".to_string();
        }
        else {
            let gender: &str ;
            if id_card_no.len() == 18 {
                if identity_card.sequence_code % 2 == 1 {
                    gender = "男";
                }
                else {
                    gender = "女";
                }
                format!("身份证号码正确,{},{:04}年{:02}月{:02}日,{}",gender,identity_card.get_birth().0,identity_card.get_birth().1,identity_card.get_birth().2,identity_card.get_location(&location_map))
            }
            else{
                let temp: i32 = identity_card.get_check_code().parse::<i32>().unwrap();
                if temp % 2 == 1 {
                    gender = "男";
                }
                else {
                    gender = "女";
                }
                format!("身份证号码正确,{},19{:02}年{:02}月{:02}日,{}",gender,identity_card.get_birth().0,identity_card.get_birth().1,identity_card.get_birth().2,identity_card.get_location(&location_map))
            }
        }
    }
}

fn location_id_parser(localfile_path: &str)-> HashMap<i32, String> {
    let mut location_map: HashMap<i32, String> = HashMap::new();
    let file_path = Path::new(localfile_path); 
    let file_content = fs::read_to_string(file_path);
    match file_content {
        Ok(content) => {
            let location_data: HashMap<String,String> = serde_json::from_str(&content).unwrap();
            for (key, value) in location_data.iter() {
                let location_id: i32 = key.parse().unwrap();
                location_map.insert(location_id, value.to_string());
            }
        }
        Err(e) => {
            println!("Error: {}", e);
        }
    }
    location_map
}
struct IdentityCard {
    location_id : i32,
    birth: i32,
    sequence_code: i32,
    check_code: String,
}


impl IdentityCard {
    fn new(location_id: i32, birth: i32, sequence_code: i32, check_code:String) -> Self {
        Self {
            location_id,
            birth,
            sequence_code,
            check_code,
        }
    }

    fn get_location(&self, location_map: &HashMap<i32, String>) -> String {
        match location_map.get(&self.location_id) {
            Some(location) => location.to_string(),
            None => "Unknown".to_string(),
        }
    }
    
    fn get_birth(&self) -> (i32, i32, i32){
        let birth_year = self.birth / 10000;
        let birth_month = (self.birth % 10000) / 100;
        let birth_day = self.birth % 100;
        (birth_year, birth_month, birth_day)
    }

    fn birth_valid_check(&self) -> bool {
        let (birth_year, birth_month, birth_day) = self.get_birth();
        if birth_month < 1 || birth_month > 12 {
            return false;
        }
        else if birth_day < 1 || birth_day > days_in_month(birth_year, birth_month) {
            return false;
        }
        else {
            return true;
        }

    }
    fn get_check_code(&self) -> &String {
        &self.check_code
    }

    fn sequence_code_valid_check(&self) -> bool {
        let weight = [4, 8, 5, 10, 9, 7, 3, 6, 1, 2, 9, 7, 5, 10, 2, 4, 8];
        let mut sum = 0;
        let mut idcard_num:Vec<i32>  = Vec::new();
        let mut location_num = self.location_id;
        let (mut birth_year, birth_month, birth_day) = self.get_birth();
        let mut sequence_num = self.sequence_code;
        while location_num > 0 {
            idcard_num.push(location_num % 10);
            location_num /= 10;
        }
        while birth_year > 0{
            idcard_num.push(birth_year % 10);
            birth_year /= 10;
        }
        idcard_num.push(birth_month%10);
        idcard_num.push(birth_month/10);
        idcard_num.push(birth_day%10);
        idcard_num.push(birth_day/10);
        while sequence_num > 0 {
            idcard_num.push(sequence_num % 10);
            sequence_num /= 10;
        }
        for i in 0..idcard_num.len() {
            sum += idcard_num[i] * weight[i];
        }

        let check_code = sum % 11;
        let check_hash: HashMap<i32,String> = [
            (0, "1".to_string()),
            (1, "0".to_string()),
            (2, "X".to_string()),
            (3, "9".to_string()),
            (4, "8".to_string()),
            (5, "7".to_string()),
            (6, "6".to_string()),
            (7, "5".to_string()),
            (8, "4".to_string()),
            (9, "3".to_string()),
            (10, "2".to_string()),
        ].iter().cloned().collect();
        
        if check_hash.get(&check_code).unwrap() == self.get_check_code() {
            return true;
        }
        else {
            println!("check_code:{}, check_hash: {}", check_code, check_hash.get(&check_code).unwrap());
            return false;
        }
    }
}

fn is_leap(year: i32) -> bool {
    (year % 4 == 0 && year % 100!= 0) || year % 400 == 0
}

fn days_in_month(year: i32, month: i32) -> i32 {
    match month{
        1 | 3 | 5 | 7 | 8 | 10 | 12 => 31,
        4 | 6 | 9 | 11 => 30,
        2 => if is_leap(year) { 29 } else { 28 },
        _ => panic !("Invalid month"),
    }
}